"""Generic AG-UI event creation utilities for any graph."""

from typing import Any
from uuid import uuid4

from pydantic import BaseModel

from haiku.rag.graph.agui.state import compute_state_delta

# Type aliases for AG-UI events (actual types from ag_ui.core will be used at runtime)
AGUIEvent = dict[str, Any]


def emit_run_started(
    thread_id: str, run_id: str, input_data: str | None = None
) -> dict[str, Any]:
    """Create a RunStarted event.

    Args:
        thread_id: Unique identifier for the conversation thread
        run_id: Unique identifier for this run
        input_data: Optional input that started the run

    Returns:
        RunStarted event dict
    """
    event: dict[str, Any] = {
        "type": "RUN_STARTED",
        "threadId": thread_id,
        "runId": run_id,
    }
    if input_data:
        event["input"] = input_data
    return event


def emit_run_finished(thread_id: str, run_id: str, result: Any) -> dict[str, Any]:
    """Create a RunFinished event.

    Args:
        thread_id: Unique identifier for the conversation thread
        run_id: Unique identifier for this run
        result: The final result of the run

    Returns:
        RunFinished event dict
    """
    # Convert result to dict if it's a Pydantic model
    if hasattr(result, "model_dump"):
        result = result.model_dump()

    return {
        "type": "RUN_FINISHED",
        "threadId": thread_id,
        "runId": run_id,
        "result": result,
    }


def emit_run_error(message: str, code: str | None = None) -> dict[str, Any]:
    """Create a RunError event.

    Args:
        message: Error message
        code: Optional error code

    Returns:
        RunError event dict
    """
    event: dict[str, Any] = {
        "type": "RUN_ERROR",
        "message": message,
    }
    if code:
        event["code"] = code
    return event


def emit_step_started(step_name: str) -> dict[str, Any]:
    """Create a StepStarted event.

    Args:
        step_name: Name of the step being started

    Returns:
        StepStarted event dict
    """
    return {
        "type": "STEP_STARTED",
        "stepName": step_name,
    }


def emit_step_finished(step_name: str) -> dict[str, Any]:
    """Create a StepFinished event.

    Args:
        step_name: Name of the step that finished

    Returns:
        StepFinished event dict
    """
    return {
        "type": "STEP_FINISHED",
        "stepName": step_name,
    }


def emit_text_message(content: str, role: str = "assistant") -> dict[str, Any]:
    """Create a TextMessageChunk event (convenience wrapper).

    This creates a complete text message in one event.

    Args:
        content: The message content
        role: The role of the sender (default: assistant)

    Returns:
        TextMessageChunk event dict
    """
    message_id = str(uuid4())
    return {
        "type": "TEXT_MESSAGE_CHUNK",
        "messageId": message_id,
        "role": role,
        "delta": content,
    }


def emit_text_message_start(message_id: str, role: str = "assistant") -> dict[str, Any]:
    """Create a TextMessageStart event.

    Args:
        message_id: Unique identifier for this message
        role: The role of the sender

    Returns:
        TextMessageStart event dict
    """
    return {
        "type": "TEXT_MESSAGE_START",
        "messageId": message_id,
        "role": role,
    }


def emit_text_message_content(message_id: str, delta: str) -> dict[str, Any]:
    """Create a TextMessageContent event.

    Args:
        message_id: Identifier for the message being streamed
        delta: Content chunk to append

    Returns:
        TextMessageContent event dict
    """
    return {
        "type": "TEXT_MESSAGE_CONTENT",
        "messageId": message_id,
        "delta": delta,
    }


def emit_text_message_end(message_id: str) -> dict[str, Any]:
    """Create a TextMessageEnd event.

    Args:
        message_id: Identifier for the message being completed

    Returns:
        TextMessageEnd event dict
    """
    return {
        "type": "TEXT_MESSAGE_END",
        "messageId": message_id,
    }


def emit_state_snapshot(state: BaseModel) -> dict[str, Any]:
    """Create a StateSnapshot event.

    Args:
        state: The complete state to snapshot (any Pydantic BaseModel)

    Returns:
        StateSnapshot event dict
    """
    return {
        "type": "STATE_SNAPSHOT",
        "snapshot": state.model_dump(),
    }


def emit_state_delta(old_state: BaseModel, new_state: BaseModel) -> dict[str, Any]:
    """Create a StateDelta event with JSON Patch operations.

    Args:
        old_state: Previous state (any Pydantic BaseModel)
        new_state: Current state (same type as old_state)

    Returns:
        StateDelta event dict
    """
    delta = compute_state_delta(old_state, new_state)
    return {
        "type": "STATE_DELTA",
        "delta": delta,
    }


def emit_activity(
    message_id: str,
    activity_type: str,
    content: dict[str, Any],
) -> dict[str, Any]:
    """Create an ActivitySnapshot event.

    Args:
        message_id: Message ID to associate activity with (required)
        activity_type: Type of activity (e.g., "planning", "searching")
        content: Structured payload representing the activity state

    Returns:
        ActivitySnapshot event dict
    """
    return {
        "type": "ACTIVITY_SNAPSHOT",
        "messageId": message_id,
        "activityType": activity_type,
        "content": content,
    }


def emit_activity_delta(
    message_id: str,
    activity_type: str,
    patch: list[dict[str, Any]],
) -> dict[str, Any]:
    """Create an ActivityDelta event with JSON Patch operations.

    Args:
        message_id: Message ID of the activity being updated
        activity_type: Type of activity being updated
        patch: JSON Patch operations to apply

    Returns:
        ActivityDelta event dict
    """
    return {
        "type": "ACTIVITY_DELTA",
        "messageId": message_id,
        "activityType": activity_type,
        "patch": patch,
    }
